package com.googlecode.yoohoo.xmppcore.protocol.parsing;

import java.util.List;

import com.googlecode.yoohoo.xmppcore.protocol.JabberId;
import com.googlecode.yoohoo.xmppcore.protocol.XmppProtocolException;
import com.googlecode.yoohoo.xmppcore.protocol.stanza.Stanza;
import com.googlecode.yoohoo.xmppcore.protocol.stanza.error.BadRequest;

public abstract class StanzaParser<T extends Stanza> implements IXmppParser<T> {
	private static final String ATTRIBUTE_NAME_ID = "id";
	private static final String ATTRIBUTE_NAME_TYPE = "type";
	private static final String ATTRIBUTE_NAME_TO = "to";
	private static final String ATTRIBUTE_NAME_FROM = "from";
	private static final String ATTRIBUTE_NAME_LANG = "lang";
	private static final String PREFIX_XML = "xml";
	
	protected T stanza;
	
	@Override
	public void processAttributes(String path, List<Attribute> attributes) {
		if (path.indexOf('/') == -1) { // root element
			stanza = createStanza();
			
			for (Attribute attribute : attributes) {
				String prefix = attribute.getPrefix();
				String localName = attribute.getLocalName();
				String value = attribute.getValue();
				
				if (PREFIX_XML.equals(prefix) && ATTRIBUTE_NAME_LANG.equals(localName)) {
					stanza.setXmlLang(value);
				} else if (prefix != null) {
					throw new XmppProtocolException(new BadRequest(String.format(
							"Unknown stanza attribute name '%s:%s'.", prefix, localName)));
				} else if (ATTRIBUTE_NAME_FROM.equals(localName)) {
					stanza.setFrom(parseJid(value));
				} else if (ATTRIBUTE_NAME_TO.equals(localName)) {
					stanza.setTo(parseJid(value));
				} else if (ATTRIBUTE_NAME_TYPE.equals(localName)) {
					try {
						stanza.setType(value);
					} catch (IllegalArgumentException e) {
						throw new XmppProtocolException(new BadRequest(String.format(
								"Invalid stanza type '%s'.", value)));
					}
				} else if (ATTRIBUTE_NAME_ID.equals(localName)) {
					stanza.setId(value);
				} else {
					throw new XmppProtocolException(new BadRequest(String.format(
							"Invalid stanza attribute '%s:%s'.", prefix, localName)));
				}				
			}
		} else {
			doProcessAttributes(path, attributes);
		}
	}

	private JabberId parseJid(String value) {
		return JabberId.parseJidString(value);
	}
	
	protected void doProcessAttributes(String path, List<Attribute> attributes) {
	}
	
	@Override
	public T getObject() {
		return stanza;
	}

	protected abstract T createStanza();
	
	@Override
	public void processEmbeddedObject(ProtocolKey pk, Object object) {
		doProcessEmbeddedObject(pk, object);
		
		if (object != null) {
			stanza.getObjects().add(object);
		}
	}
	
	protected void doProcessEmbeddedObject(ProtocolKey pk, Object object) {
	}
}
